package cn.jinbyte.starter.message.service;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.jinbyte.core.exception.BussException;
import cn.jinbyte.data.service.CacheService;
import cn.jinbyte.starter.message.config.EmailCodeProperties;
import cn.jinbyte.starter.message.model.EmailNoticeDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱验证码服务
 */
@Slf4j
public class EmailCodeService {
    public static final String SENT_KEY_SUFFIX = ":sentTime";
    private final EmailCodeProperties properties;
    private final EmailNoticeService emailNoticeService;
    private final CacheService<String> cache;

    public EmailCodeService(EmailNoticeService emailNoticeService,
                            EmailCodeProperties properties,
                            CacheService<String> cache) {
        this.emailNoticeService = emailNoticeService;
        this.properties = properties;
        this.cache = cache;
    }

    /**
     * 生成验证码
     *
     * @return java.lang.String
     */
    private String generateEmailCode() {
        //生成6位数字验证码
        int code = (int) ((Math.random() * 9 + 1) * 100000);
        return String.valueOf(code);
    }

    private String getCacheKey(String id, String email) {
        return properties.getCachePrefix() + email + id;
    }

    /**
     * 生成并发送邮箱短信验证码
     *
     * @param email 邮箱
     * @return int 0-成功， -1-发送失败 -2-操作频繁
     */
    public String send(String email) {
        if (isInLimitRange(email)) {
            throw new BussException("操作频繁");
        }
        String emailCode = generateEmailCode();
        String emailMessage = MessageFormat.format(properties.getTemplate(), emailCode, properties.getTimeout());

        emailNoticeService.send(EmailNoticeDTO.builder()
                .to(email)
                .subject("【jinbyte.cn】验证码")
                .content(emailMessage)
                .build());
        // 缓存验证码
        String id = IdUtil.simpleUUID();
        String cacheKey = getCacheKey(id, email);

        cache.set(cacheKey, emailCode, properties.getTimeout(), TimeUnit.MINUTES);
        // 缓存验证码发送时间
        String sentTimeKey = cacheKey + SENT_KEY_SUFFIX;
        cache.set(sentTimeKey, DateUtil.now(), 60, TimeUnit.SECONDS);
        return id;
    }


    /**
     * 校验邮箱验证码
     *
     * @param email     邮箱
     * @param emailCode 邮箱验证码
     */
    public void validate(String id, String email, String emailCode) {
        String cacheKey = getCacheKey(id, email);
        String sentTimeKey = cacheKey + SENT_KEY_SUFFIX;
        if (!properties.isOpenValidate()) {
            cache.del(cacheKey);
            cache.del(sentTimeKey);
            return;
        }
        Object cacheObject = cache.get(cacheKey);
        if (Objects.isNull(cacheObject)) {
            throw new BussException("验证码已过期");
        }
        if (!StringUtils.equals(cacheObject.toString(), emailCode)) {
            throw new BussException("验证码错误");
        }
        cache.del(cacheKey);
        cache.del(sentTimeKey);
    }

    private boolean isInLimitRange(String email) {
        String lastTimeKey = properties.getCachePrefix() + email + SENT_KEY_SUFFIX;
        String lastSendTime = cache.get(lastTimeKey);
        if (StringUtils.isEmpty(lastSendTime)) {
            return false;
        }
        // 根据上次发送时间计算发送限制结束时间
        DateTime dateTime = DateUtil.parse(lastSendTime, "yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateTime);
        calendar.add(Calendar.SECOND, properties.getTimeInterval());
        Date limitEndTime = calendar.getTime();
        // 判断当前时间是否在发送限制结束时间前
        Date now = new Date();
        return now.before(limitEndTime);
    }
}
